Skip to content

test: drop best-effort catches from container-fixture teardown#85

Merged
ANcpLua merged 1 commit into
mainfrom
claude/fixture-dispose-no-swallow
Jun 26, 2026
Merged

test: drop best-effort catches from container-fixture teardown#85
ANcpLua merged 1 commit into
mainfrom
claude/fixture-dispose-no-swallow

Conversation

@ANcpLua

@ANcpLua ANcpLua commented Jun 26, 2026

Copy link
Copy Markdown
Owner

What

The integration-test ContainerFixtureBase.DisposeAsync swallowed every teardown fault behind try { … } catch { /* best-effort */ } — one per container plus the SUT. The same blanket swallow lived in SharedContainerFixture.DisposeSutAsync (_host.StopAsync). This is a code smell: it hides real disposal/shutdown bugs forever.

Replaced with plain null-guarded awaits — errors now surface.

Why the swallow was safe to delete

The catches existed to stop a failed InitializeAsync (e.g. a Testcontainers wait-strategy timeout) from being masked by a secondary NRE during xUnit cleanup. That masking risk no longer exists: both DisposeSutAsync overrides already null-guard their SUT —

  • SharedRestContainerFixture: if (_factory is not null) await _factory.DisposeAsync();
  • SharedContainerFixture: if (_host is not null) { … }

so a failed init cannot NRE during cleanup. The blanket catches only suppressed genuine teardown faults. (xUnit v3 also aggregates lifecycle exceptions, so an init failure isn't lost even if teardown were to throw.)

Pattern source

Matches the Microsoft Agent Framework test-fixture idiom — plain null-guarded awaits, no best-effort catch — e.g. ConformanceTestBase / SessionPersistenceTests:

this._client?.Dispose();
if (this._app != null) await this._app.DisposeAsync();

Teardown order is SUT-first (it consumes the containers) then infra; Testcontainers' Ryuk reaper cleans up anything a mid-teardown throw leaves running.

Verification

  • dotnet build of PaperlessServices.Tests + PaperlessREST.Tests (→ Paperless.TestSupport): Build succeeded, 0 warnings, 0 errors.
  • Integration suite (Postgres/RabbitMQ/MinIO/ES via Testcontainers) runs in the required Build & Test (backend) CI job — that is the runtime gate.

Complete and compile-verified. No production code touched; test-fixture teardown only.

🤖 Generated with Claude Code

The integration-fixture DisposeAsync wrapped every container Dispose and the
SUT teardown in `try { ... } catch { /* best-effort */ }`, swallowing all
teardown faults to keep a failed InitializeAsync from being masked by a
secondary cleanup error.

That masking risk is gone: both DisposeSutAsync overrides already null-guard
their SUT (_factory / _host), so a failed init cannot NRE during cleanup. The
blanket catches only hid genuine teardown bugs from ever surfacing.

Replace them with plain null-guarded awaits, matching the Microsoft Agent
Framework test-fixture idiom (ConformanceTestBase / SessionPersistenceTests:
`client?.Dispose(); if (_app != null) await _app.DisposeAsync();`). Teardown
order is SUT-first (it consumes the containers) then infra; Testcontainers'
Ryuk reaper cleans up anything a mid-teardown throw leaves running. Also drop
the same swallow from SharedContainerFixture.DisposeSutAsync (_host.StopAsync).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (2)
  • Paperless.TestSupport/ContainerFixtureBase.cs is excluded by none and included by none
  • PaperlessServices.Tests/Integration/WorkerTestBase.cs is excluded by none and included by none

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ed736c5c-21dc-495d-bfd5-3fc47550d500

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@ANcpLua ANcpLua merged commit f3947bd into main Jun 26, 2026
7 checks passed
@ANcpLua ANcpLua deleted the claude/fixture-dispose-no-swallow branch June 26, 2026 05:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant